home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Sample Code / Sample Editors⁄Viewers / Draw Editor / Source / Link.cpp < prev    next >
Encoding:
Text File  |  1995-12-11  |  59.9 KB  |  1,978 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Link.cpp
  3.  
  4.     Contains:    Link Classes Implementation
  5.  
  6.     Written by:    Mike Halpin
  7.     
  8.     Copyright:    © 1995 by Apple Computer, Inc., all rights reserved.
  9. */
  10.  
  11. // -- DrawEditor Includes --
  12.  
  13. #ifndef _COMPILERDEFS_
  14. #include "CompDefs.h"
  15. #endif
  16.  
  17. // -- DrawEditor Includes --
  18.  
  19. #ifndef _LINK_
  20. #include "Link.h"
  21. #endif
  22.  
  23. #ifndef _DRAWEDITOR_
  24. #include "DrawEditor.h"
  25. #endif
  26.  
  27. #ifndef _SELECTION_
  28. #include "Selection.h"
  29. #endif
  30.  
  31. #ifndef _SHAPES_
  32. #include "Shapes.h"
  33. #endif
  34.  
  35. #ifndef _DRAWEDITORUTILS_
  36. #include "DrawEditorUtils.h"
  37. #endif
  38.  
  39. #ifndef _PROMISE_
  40. #include "Promise.h"
  41. #endif
  42.  
  43. #ifndef _LINKCOMMANDS_
  44. #include "LinkCommands.h"
  45. #endif
  46.  
  47. // -- OpenDoc Includes --
  48.  
  49. #ifndef SOM_Module_OpenDoc_StdProps_defined
  50. #include <StdProps.xh>
  51. #endif
  52.  
  53. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  54. #include <StdTypes.xh>
  55. #endif
  56.  
  57. #ifndef SOM_ODStorageUnit_xh
  58. #include <StorageU.xh>
  59. #endif
  60.  
  61. #ifndef SOM_ODLink_xh
  62. #include <Link.xh>
  63. #endif
  64.  
  65. #ifndef SOM_ODLinkSpec_xh
  66. #include <LinkSpec.xh>
  67. #endif
  68.  
  69. #ifndef SOM_ODLinkSource_xh
  70. #include <LinkSrc.xh>
  71. #endif
  72.  
  73. // -- OpenDoc Utilities --
  74.  
  75. #ifndef _ODUTILS_
  76. #include "ODUtils.h"
  77. #endif
  78.  
  79. #ifndef _STORUTIL_
  80. #include "StorUtil.h"
  81. #endif
  82.  
  83. #ifndef _ODMEMORY_
  84. #include "ODMemory.h"            // ODDisposePtr
  85. #endif
  86.  
  87. #ifndef _ODDEBUG_
  88. #include "ODDebug.h"
  89. #endif
  90.  
  91. #ifndef _UTILERRS_
  92. #include "UtilErrs.h"
  93. #endif
  94.  
  95. #ifndef _TEMPITER_
  96. #include "TempIter.h"
  97. #endif
  98.  
  99. // -- Toolbox Includes --
  100.  
  101. #ifndef mathRoutinesIncludes
  102. #include <math routines.h>
  103. #endif
  104.  
  105. #ifndef __MEMORY__
  106. #include <memory.h>
  107. #endif
  108.  
  109.         
  110. //=============================================================================
  111. //    class CPublishLink
  112. //=============================================================================
  113.  
  114. //---------------------------------------------------------------------------------------
  115. //    CPublishLink::CPublishLink
  116. //
  117. //    Description:    This constructor is called from a CCutCopyShapeCommand or a
  118. //    CDragShapeCommand.  The commands pass in a list of unsubscribed shapes and a
  119. //  list of CSubscribeLink's.  The CSubscribeLink's provide the as yet unpublished
  120. //    link with safe access to the contained subscribed shapes, in the event that
  121. //    those shapes are replaced during an update before publishing occurs.
  122. //---------------------------------------------------------------------------------------
  123.  
  124. CPublishLink::CPublishLink(    ODUpdateID updateID, 
  125.                             CSelection* selection, 
  126.                             COrderedList* shapeList,
  127.                             COrderedList* subscribeLinks)
  128. {
  129.     fODLinkSource = kODNULL;
  130.     fODID = kODNULL;
  131.     
  132.     fUpdateID = updateID;
  133.     fPendingID = updateID;
  134.     
  135.     fSelection = selection;
  136.     fDrawEditor = selection->GetDrawEditor();
  137.     
  138.     fWasRemoved = kODFalse;
  139.     fPublished = kODFalse;
  140.     fNewlyPublished = kODFalse;
  141.     
  142.     fSelectedCount = 0;
  143.     fPromise = kODNULL;
  144.     fPublishContent = kODNULL;
  145.     
  146.     fShapeList = shapeList;
  147.     fSubscribeLinks = subscribeLinks;
  148.     
  149.     fHasCommandOutstanding = kODFalse;
  150.         
  151. }
  152.  
  153. //---------------------------------------------------------------------------------------
  154. //    CPublishLink::CPublishLink
  155. //
  156. //     Description:    This constructor is called by the selection's content object when it 
  157. //  finds a link to internalize. This does not initialize any real data because that will
  158. //    be done in InternalizeLink and PostCloneInternalizeLink.
  159. //---------------------------------------------------------------------------------------
  160.  
  161. CPublishLink::CPublishLink(CSelection* selection)
  162. {
  163.     
  164.     fODLinkSource = kODNULL;
  165.     fODID = kODNULL;
  166.     
  167.     fUpdateID = kODNULL;
  168.     fPendingID = kODNULL;
  169.     
  170.     fSelection = selection;
  171.     fDrawEditor = selection->GetDrawEditor();
  172.     
  173.     fWasRemoved = kODFalse;
  174.     fPublished = kODFalse;
  175.     fNewlyPublished = kODFalse;
  176.  
  177.     fSelectedCount = 0;
  178.     fPromise = kODNULL;
  179.     
  180.     fShapeList = new COrderedList;
  181.     fSubscribeLinks = new COrderedList;
  182.     fPublishContent = kODNULL;
  183.  
  184.     fHasCommandOutstanding = kODFalse;
  185. }
  186.  
  187.  
  188. //---------------------------------------------------------------------------------------
  189. //    CPublishLink::~CPublishLink
  190. //---------------------------------------------------------------------------------------
  191.  
  192. CPublishLink::~CPublishLink()
  193. {
  194.     ODSafeReleaseObject(fODLinkSource);
  195.     
  196.     // Here's why we don't need to 'Unpublish' our shapes and contained subscribe links:
  197.     
  198.     // A. When deleted because it failed to be internalize after cloning, then CShape::Publish was not called, so 
  199.     //          there are no references.
  200.     // B. When called due to commiting a removal of a link, all the contained objects are being commited
  201.     //             out of existance as well, so who cares
  202.     // C. When called due to commiting the Breaking of the link, then each contained object had to be 'Unpublished'
  203.     //             when the link was broken.
  204.     
  205.     // If we were ever published, fShapeList & fPublishContent are  owned by fPromise so just delete the promise, 
  206.     
  207.     if (fPromise)
  208.         delete fPromise;
  209.     else
  210.         delete fShapeList;
  211.         
  212.     delete fSubscribeLinks;
  213.  
  214.         
  215. }
  216.  
  217. //---------------------------------------------------------------------------------------
  218. //    CPublishLink::Publish
  219. //
  220. //    Description:    This is called from CreateLink when the link has not been published.
  221. //    Also used for 'Undo Break Link Source'.  It establishes referneces to this object
  222. //  in each contained CShape and CSubscribe link.
  223. //---------------------------------------------------------------------------------------
  224.  
  225. void    CPublishLink::Publish(Environment* ev)
  226. {
  227.     // In it's published state, a CPublishLink just contains a list of all it's shapes.  That's what
  228.     // CDrawContent::Externalize knows how to deal with.  In that state, any included CSubscribeLink objects
  229.     // can dynamically replace shapes in the publisher during link updates, because the CSubscribeLink contains
  230.     // a pointer to each containing publisher
  231.     
  232.     // However, here in the pre-published (pending) or unpublished (broken) state, our content, including
  233.     // contained subscribers do not contain a reference  to the this object.  In this state, we have a list
  234.     // only of unsubscribed shapes and a list of CSubscribeLink's.  Publishing converts that format into 
  235.     // a list of shapes (sutibalbe for externalzing when we update the ODLinkSource object), while
  236.     // adding the necessary references to this object to each CShape and each CSubscribeLink.
  237.     
  238.     // This is one of several areas that could be simplified if CSubscribeLink was derived from CShape.
  239.     // and no attempt was made to maintain other direct references to any subscribed content.
  240.     
  241.     if (!fPublished)
  242.     {
  243.         fPublished = kODTrue;
  244.         
  245.         // The first time we get published, we need to create an ODLinkSource.
  246.         if (!fODLinkSource)
  247.         {
  248.             fODLinkSource = fDrawEditor->GetDraft(ev)->CreateLinkSource(ev, fDrawEditor->GetODPart());
  249.             fNewlyPublished = kODTrue;   // true until first update completes.
  250.         }
  251.         
  252.         COrdListIterator shapeIter(fShapeList);
  253.         for (CShape* shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
  254.         {
  255.             if (shape->IsSelected())
  256.                 fSelectedCount++;
  257.     
  258.             shape->Publish(ev, this);
  259.                         
  260.         }
  261.         
  262.         // CSubscribeLink::Publish, besides establishing a reference to this, adds each subscribed shape
  263.         // to our shape list so that we have a simple list of shapes for externalizing when we update the
  264.         // link source.
  265.         
  266.         while (fSubscribeLinks->Count() != 0)
  267.         {
  268.             CSubscribeLink* sLink = (CSubscribeLink*)fSubscribeLinks->RemoveFirst();
  269.             sLink->Publish(ev, this);  
  270.         }
  271.             
  272.         ASSERT(fShapeList->Count() != 0, kODErrAssertionFailed);
  273.         
  274.         if (fSelectedCount == fShapeList->Count())
  275.             fSelection->AddPublishLink(this);
  276.             
  277.             
  278.         // There's no need to create a new link promise with the same content every time
  279.         // we externalize. This constructor just copies fShapeList reference, not the list itself, 
  280.         // so changes to fShapeList are automatically reflected in the promise's content.
  281.             
  282.         if (!fPromise)
  283.         {
  284.             fPromise = new CPromise(fDrawEditor, fDrawEditor->GetFirstSourceFrame(ev), fShapeList, kODCloneToLink);
  285.             fPublishContent = fPromise->GetPromiseContent();
  286.         }
  287.         
  288.         // Add the link to the part's content.
  289.         this->AddToPart(ev);
  290.     }
  291. }
  292.  
  293. //---------------------------------------------------------------------------------------
  294. //    CPublishLink::PostCloneInternalizeLink
  295. //    
  296. //    Description:    Internalize the ODLinkSource from the storage ID read in 
  297. //    in InternalizeLink. If successful, wire up any contained shapes and any
  298. //     contained subscribe links so that the are 'Published' by this link source.
  299. //    This is equivalent of Publish in its result, only starting from a different
  300. //     state.
  301. //---------------------------------------------------------------------------------------
  302.  
  303. ODBoolean CPublishLink::PostCloneInternalizeLink(Environment* ev,  ODDraft* toDraft, CShape* shape)
  304. {
  305.     ODBoolean result = kODTrue;
  306.  
  307.     // for the case of a single embedded part, a shape object was not created until
  308.     // after cloning was done, so we had to defer attatching it to any links.
  309.  
  310.     if (shape)
  311.     {
  312.         this->AddShape(shape);
  313.     }
  314.     
  315.     if (fODLinkSource == kODNULL)
  316.     {            
  317.         result = toDraft->IsValidID(ev, fODID);
  318.         
  319.         if (result)
  320.             fODLinkSource = toDraft->AcquireLinkSource(ev, fODID);
  321.     }
  322.     
  323.     // This is a lot like Publish, but doesn't have the advantage of a ready made 
  324.     // list of subscribe links and a filtered list of shapes to start with.
  325.     if (result)
  326.     {
  327.         COrderedList tempList;
  328.         
  329.         COrdListIterator shapeIter(fShapeList);
  330.         for (CShape* shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
  331.         {
  332.             // When the shapes were added, they were not yet part of the selection, even if it was
  333.             // the Selection content that was internalizing. If the shapes were added to the selection
  334.             // then it was before they pointed to this publish link.  The link itself is already in
  335.             // the appropriate content list, so we just need to update fSelectedCount
  336.             
  337.             if (shape->IsSelected())
  338.                 ++fSelectedCount;
  339.                 
  340.             CSubscribeLink* sLink = shape->GetSubscribeLink();
  341.             
  342.             if (!sLink)
  343.                 shape->Publish(ev, this);
  344.             else
  345.             {
  346.                 tempList.Remove(sLink);   // does nothing if not already there
  347.                 tempList.AddFirst(sLink); // makes removal efficient when consecutive shapes have same subscriber
  348.             }
  349.         }
  350.         
  351.         while(tempList.Count() != 0)
  352.         {
  353.             CSubscribeLink* sLink = (CSubscribeLink*)tempList.RemoveFirst();
  354.             sLink->GetPublishLinks()->AddLast(this);
  355.         }    
  356.         
  357.         fPromise = new CPromise(fDrawEditor, fDrawEditor->GetFirstSourceFrame(ev), fShapeList, kODCloneToLink);
  358.         fPublishContent = fPromise->GetPromiseContent();
  359.         fPublished = kODTrue;
  360.     
  361.     }
  362.         
  363.     return result;
  364.     
  365. }
  366.  
  367. //---------------------------------------------------------------------------------------
  368. //    CPublishLink::Unpublish
  369. //
  370. //    Description:    Convert the content model from a list of shapes to a list of non-subscribed
  371. //    shapes and a list of CSubscribeLink's.  Unpublish everything and remove the link from
  372. //     the part's content model.
  373. //---------------------------------------------------------------------------------------
  374.  
  375. void CPublishLink::Unpublish(Environment* ev)
  376. {
  377.  
  378.     if (fPublished)
  379.     {
  380.         CShape* shape;
  381.         
  382.         // before we mess anything up, we need to see if this link is part of 
  383.         // a clipboard promise.  This would be true iff all our content is
  384.         // in a clipboard promise.  
  385.         
  386.         ODBoolean promised = kODTrue;
  387.         
  388.         COrdListIterator ite(fShapeList);
  389.         for (shape = (CShape*)ite.First(); ite.IsNotComplete(); shape = (CShape*)ite.Next())
  390.         {
  391.             if (!shape->IsPromisedToClipboard())
  392.             {
  393.                 promised = kODFalse;
  394.                 break;
  395.             }
  396.         }
  397.         
  398.         if (promised)
  399.             ::ResolveClipboardPromises(ev, fDrawEditor->GetSession(ev));
  400.         
  401.  
  402.         fPublished = kODFalse;
  403.         
  404.         this->RemoveFromPart(ev);
  405.     
  406.         // This stuff won't be maintained while the link is broken. It'll be restored
  407.         // to the current state if and when this is undone.
  408.         
  409.         if (fSelectedCount == fShapeList->Count())
  410.             fSelection->RemovePublishLink(this);
  411.         
  412.         fSelectedCount = 0;
  413.         
  414.         // This restores the content to the format expected by Publish so that this action
  415.         // can be undone. This format replaces any shapes that are subscribed with references
  416.         // to the CSubscribeLink object.  That protects us from having dangling shape references in
  417.         // the event that the subscribe link updates while it is not 'Published' by this CPublishLink.
  418.         
  419.         CShape* newFirstShape = kODNULL;
  420.         
  421.         while ((shape = (CShape*)fShapeList->First()) != newFirstShape)
  422.         {
  423.             fShapeList->RemoveFirst();
  424.             CSubscribeLink* sLink = (CSubscribeLink*)shape->GetSubscribeLink();
  425.             if (!sLink)
  426.             {
  427.                 shape->Unpublish(ev, this);        // Remove shape's pointer to this publisher
  428.                 fShapeList->AddLast(shape);        // Put shape back on the end of our shape list
  429.                 if(!newFirstShape)
  430.                     newFirstShape = shape;        // So we'll know when to stop
  431.             }
  432.             else
  433.             {
  434.                 fSubscribeLinks->Remove(sLink);      // prevents duplicates, does nothting unless sLink is already there
  435.                 fSubscribeLinks->AddFirst(sLink);
  436.             }
  437.             
  438.         }
  439.         
  440.         COrdListIterator linkIter(fSubscribeLinks);
  441.         for (CSubscribeLink* sLink = (CSubscribeLink*)linkIter.First(); linkIter.IsNotComplete(); sLink = (CSubscribeLink*)linkIter.Next())
  442.         {
  443.             sLink->Unpublish(ev, this);
  444.         }
  445.             
  446.         // Since we'll no longer be informed of shapes being selected clear the count
  447.         // it will be recalculated correctly if and when we are republished.
  448.         fSelectedCount = 0;
  449.     }
  450. }
  451.  
  452. //---------------------------------------------------------------------------------------
  453. //    CPublishLink::AddToPart
  454. //
  455. //    Description:    Add the link to the par't content model, and set the ODLinkSource's
  456. //    part.
  457. //---------------------------------------------------------------------------------------
  458.  
  459. void CPublishLink::AddToPart(Environment* ev)
  460. {
  461.     fDrawEditor->AddPublishLink(this);
  462.     this->SetSourcePart(ev);
  463.     
  464.     fWasRemoved = kODFalse;
  465. }
  466.  
  467.  
  468. //---------------------------------------------------------------------------------------
  469. //    CPublishLink::RemoveFromPart
  470. //
  471. //    Description:    Remove the link from the par't content model, and clear the ODLinkSource's
  472. //    part.
  473. //---------------------------------------------------------------------------------------
  474.  
  475. void CPublishLink::RemoveFromPart(Environment *ev)
  476. {
  477.     
  478.     fDrawEditor->RemovePublishLink(ev, this);
  479.     fODLinkSource->SetSourcePart(ev, kODNULL);
  480.     
  481.     fWasRemoved = kODTrue;
  482. }
  483.  
  484.  
  485. //---------------------------------------------------------------------------------------
  486. //    CPublishLink::SetSourcePart
  487. //
  488. //    Description:  Set's the ODLinkSource's 'owning' part.
  489. //---------------------------------------------------------------------------------------
  490.  
  491. void CPublishLink::SetSourcePart(Environment* ev)
  492. {
  493.     fODLinkSource->SetSourcePart(ev, fDrawEditor->GetODPart()->GetStorageUnit(ev));
  494. }
  495.  
  496. //---------------------------------------------------------------------------------------
  497. //    CPublishLink::ContentUpdated
  498. //
  499. //    Description:    This updates the ODLinkSourceObject if appropriate.
  500. //---------------------------------------------------------------------------------------
  501.  
  502. void CPublishLink::ContentUpdated(Environment* ev, ODUpdateID updateID, ODBoolean forceUpdate)
  503. {
  504.  
  505.     // special case, only from create link when new destination is being established
  506.     // to an already functioning link. This case is actually only relevant if
  507.     // promises for multiple representations are written.  Otherwise, we don't actually
  508.     // need to anything in that case.
  509.     
  510.     ODBoolean justRewrite = forceUpdate && (updateID == kODUnknownUpdate)
  511.                             && (fUpdateID == fODLinkSource->GetUpdateID(ev));
  512.     
  513.     // replace a null id with the current id.  In the justRewrite case, using the
  514.     // old id prevents unecessary destination updates from occuring.
  515.     updateID = updateID ? updateID : fUpdateID;
  516.     
  517.         
  518.     if(forceUpdate || fODLinkSource->IsAutoUpdate(ev))
  519.     {
  520.         ODLinkKey key;
  521.         
  522.         if (fODLinkSource->Lock(ev, 0, &key)) 
  523.         {
  524.             
  525.             TRY
  526.                 fODLinkSource->Clear(ev, updateID, key);
  527.     
  528.                 ODStorageUnit* linkSU = fODLinkSource->GetContentStorageUnit(ev, key);
  529.                                 
  530.                 this->ExternalizeLinkContent(ev, linkSU);
  531.                     
  532.                 // Calling ContentUpated insures that link cycle protection is excersized.
  533.                 // Not calling it when we're just rewriting promises (ie our content hasn't changed)
  534.                 // allows us to re-use the old update id without triggering the link cycle dialog.
  535.                 if (!justRewrite)
  536.                     fODLinkSource->ContentUpdated(ev, updateID, key);
  537.                             
  538.             CATCH_ALL
  539.             
  540.                 fODLinkSource->Clear(ev, fUpdateID, key);
  541.                 fODLinkSource->Unlock(ev, key);    
  542.                 
  543.                 if (fNewlyPublished)
  544.                 {
  545.                     this->Unpublish(ev);
  546.                     fODLinkSource->Release(ev);
  547.                     fODLinkSource = kODNULL;
  548.                     fNewlyPublished = kODFalse;
  549.                 }
  550.                 
  551.                 RERAISE;
  552.                 
  553.             ENDTRY
  554.             
  555.             fODLinkSource->Unlock(ev, key);        
  556.             fNewlyPublished = kODFalse;
  557.         }
  558.         
  559.     }
  560.     
  561.     fUpdateID = updateID;
  562. }
  563.  
  564. //---------------------------------------------------------------------------------------
  565. //    CPublishLink::ExternalizeLinkContent
  566. //
  567. //    Description:    Write the source content or a promise out to the links storage unit
  568. //---------------------------------------------------------------------------------------
  569.  
  570. void    CPublishLink::ExternalizeLinkContent(Environment* ev, ODStorageUnit* linkSU)
  571. {    
  572.  
  573.     ODDraft* fromDraft = fDrawEditor->GetDraft(ev);
  574.     ODDraft* dstDraft = linkSU->GetDraft(ev);
  575.  
  576.     // Create clone info
  577.     CCloneInfo info(0, fromDraft, fDrawEditor->GetFirstSourceFrame(ev), kODCloneToLink);
  578.     
  579.     // Either write a promise, or externalize a single embedded frame
  580.     CEmbeddingShape* tShape = fPublishContent->IsOneEmbeddedShape(ev);
  581.     if (tShape)
  582.     {
  583.         ODFrame* embeddedFrame = tShape->
  584.                 GetEmbeddedFacet(ev, fDrawEditor->GetFirstSourceFrame(ev))->GetFrame(ev);
  585.                 
  586.         fPublishContent->ExternalizeSingleEmbeddedFrame( ev, 
  587.                                                     linkSU, 
  588.                                                     &info, 
  589.                                                     embeddedFrame);
  590.     }
  591.     else
  592.     {
  593.         // Focus to the content property
  594.         ODSUForceFocus(ev, linkSU, kODPropContents, kDrawEditorKind);
  595.     
  596.         // There's no real gain in writing promises to links unless
  597.         // there are multiple representations. This is just a demonstration.
  598.                             
  599.         fPromise->Promise(ev, linkSU);
  600.     }
  601.         
  602. }
  603.  
  604.  
  605. //---------------------------------------------------------------------------------------
  606. //    CPublishLink::AddShape
  607. //
  608. //    Description:  Add a shape to the source content.
  609. //---------------------------------------------------------------------------------------
  610.  
  611. void CPublishLink::AddShape(CShape* shape)
  612. {
  613.     // A CPublishLink which was entirely removed, never had any shapes removed from it
  614.     // so that it could still fulfill a promise in the case that the removal was from a cut,
  615.     // so we don't do anything in that case.
  616.     
  617.     if (!fWasRemoved)
  618.     {
  619.         fShapeList->AddLast(shape);
  620.         if (shape->IsSelected())
  621.             fSelectedCount++;
  622.     }
  623. }
  624.  
  625.  
  626. //---------------------------------------------------------------------------------------
  627. //    CPublishLink::AddShape
  628. //
  629. //    Description:  Add and publish a shape.
  630. //---------------------------------------------------------------------------------------
  631.  
  632. void CPublishLink::AddShape(Environment* ev, CShape* shape)
  633. {
  634.     // Note that this does nothing if the shape is a subscriber.  In that case any publishing
  635.     // related behavior is managed by it's subscribe link.
  636.     
  637.     shape->Publish(ev, this);
  638.     
  639.     this->AddShape(shape);
  640. }
  641.  
  642.  
  643. //---------------------------------------------------------------------------------------
  644. //    CPublishLink::RemoveShape
  645. //
  646. //    Description:    Remove a shape from the source content
  647. //---------------------------------------------------------------------------------------
  648.  
  649. void CPublishLink::RemoveShape(CShape *shape)
  650. {
  651.     //(MH)  A CPublishLink which is entirely removed, does not have any shapes removed from it
  652.     // so that it can still fulfill a promise in the case that the removal was from a cut.
  653.     // so we don't do anything in that case.
  654.     
  655.     if (!fWasRemoved)
  656.     {
  657.         // Shapes are only removed from here when being removed from the content model, we allow the shape
  658.         // to continue pointing to the publisher, so it can be replaced when added back to the content
  659.         // if the action is reversed.
  660.         
  661.         fShapeList->Remove(shape);
  662.         if (shape->IsSelected())
  663.             fSelectedCount--;
  664.     }
  665. }
  666.  
  667.  
  668. //---------------------------------------------------------------------------------------
  669. //    CPublishLink::ShapeSelected
  670. //
  671. //    Description:    As shapes are selected and unselected, they inform any links they are
  672. //                    involved in.  By keeping track of how many of this links shapes are
  673. //                    selected we can tell efficiently when the link itself should be added
  674. //                    and removed from the selection. Only a fully selected link is extenalized
  675. //                    during as part of the selection.                    
  676. //---------------------------------------------------------------------------------------
  677.  
  678. void CPublishLink::ShapeSelected(ODBoolean selectState)
  679. {
  680.     short oldCount = fSelectedCount;
  681.     
  682.     if (selectState)
  683.     {
  684.         ++fSelectedCount;
  685.         ASSERT_NOT_NULL(fSelectedCount <= fShapeList->Count());
  686.         
  687.         if (fSelectedCount == fShapeList->Count())
  688.         {
  689.             fSelection->AddPublishLink(this);
  690.         }
  691.     }
  692.     else
  693.     {
  694.         --fSelectedCount;
  695.         ASSERT_NOT_NULL(fSelectedCount >= 0);
  696.         
  697.         if (oldCount == fShapeList->Count())
  698.         {
  699.             fSelection->RemovePublishLink(this);
  700.         }
  701.         
  702.     }
  703.  
  704. }
  705.  
  706. //---------------------------------------------------------------------------------------
  707. //    CPublishLink::Count
  708. //
  709. //    Description:    How many shapes in the source content
  710. //---------------------------------------------------------------------------------------
  711.  
  712. ODULong CPublishLink::Count()
  713. {
  714.     return fShapeList->Count();
  715. }
  716.  
  717. //---------------------------------------------------------------------------------------
  718. //    CPublishLink::ExternalizeLink
  719. //
  720. //    Description:    Write out our private format for externalizing a link source.
  721. //---------------------------------------------------------------------------------------
  722.  
  723. void CPublishLink::ExternalizeLink(Environment *ev, ODStorageUnit* su, CCloneInfo* cloneInfo)
  724. {
  725.     ODID linkSourceID =  this->GetODLinkSource()->GetID(ev);
  726.     ODBoolean valid = kODTrue;
  727.     
  728.     if (cloneInfo)
  729.     {
  730.         linkSourceID = cloneInfo->fFromDraft->Clone(ev, cloneInfo->fKey, linkSourceID , kODNULLID, kODNULLID);
  731.         valid = cloneInfo->fFromDraft->IsValidID(ev, linkSourceID);
  732.     }
  733.     
  734.     if (valid)
  735.     {        
  736.         // store the number of shapes. This first, because we use 0  shape count as
  737.         // tag for an invalid source link. 
  738.         ODUShort shapeCnt = fShapeList->Count();
  739.  
  740.         StorageUnitSetValue(su, ev, sizeof(ODUShort), &shapeCnt);
  741.         
  742.         // store a reference to the link
  743.         ODStorageUnitRef    aSURef ;
  744.         su->GetStrongStorageUnitRef(ev, linkSourceID, aSURef);
  745.         StorageUnitSetValue(su, ev, kODStorageUnitRefSize, &aSURef);
  746.         
  747.         // store the current update id
  748.  
  749.         StorageUnitSetValue(su, ev, sizeof(ODUpdateID), &fUpdateID);
  750.         
  751.         // store the export indices for each shape in the link.
  752.         COrdListIterator iter(fShapeList);
  753.         for (CShape *shape = (CShape*)iter.First(); iter.IsNotComplete(); shape = (CShape*)iter.Next())
  754.         {
  755.             ODUShort extInd = shape->GetExternalizationIndex();
  756.             StorageUnitSetValue(su, ev, sizeof(ODUShort), &extInd);
  757.         }
  758.     }
  759.     else
  760.     {
  761.         ODUShort invalShapeCnt = 0;
  762.         StorageUnitSetValue(su, ev, sizeof(ODUShort), &invalShapeCnt);
  763.     }
  764.         
  765. }
  766.  
  767. //---------------------------------------------------------------------------------------
  768. //    CPublishLink::InternalizeLink
  769. //
  770. //    Description:    Read in our private representation of a link source.
  771. //---------------------------------------------------------------------------------------
  772.  
  773. ODBoolean CPublishLink::InternalizeLink( Environment *ev,  ODStorageUnit *su,  CCloneInfo *cloneInfo, CShape** shapeTable)
  774. {
  775.     ODUShort count;
  776.     StorageUnitGetValue(su, ev, sizeof(ODUShort), &count);
  777.     
  778.     if (count == 0)  // link was invalid from the git go
  779.         return kODFalse;
  780.         
  781.     ODBoolean validLink = kODTrue;
  782.     ODVolatile(validLink);
  783.     
  784.     TRY
  785.         
  786.         ODStorageUnitRef    aSURef;
  787.         StorageUnitGetValue(su, ev, kODStorageUnitRefSize, &aSURef);
  788.         
  789.         validLink = su->IsValidStorageUnitRef(ev, aSURef) ;
  790.         
  791.         StorageUnitGetValue(su, ev, sizeof(ODUpdateID), &fUpdateID);
  792.         
  793.         if (validLink )
  794.         {
  795.             // we have a validated su ref for the link, so clone and get the link
  796.             fODID = su->GetIDFromStorageUnitRef(ev, aSURef);
  797.  
  798.             if (cloneInfo)
  799.                 fODID = cloneInfo->fFromDraft->Clone(ev, cloneInfo->fKey, fODID, kODNULLID, kODNULLID);            
  800.         }
  801.         
  802.         for (ODUShort k = 0; k < count; k++)
  803.         {
  804.             ODUShort intIndex;
  805.             StorageUnitGetValue(su, ev, sizeof(short), &intIndex);
  806.             
  807.             if(validLink && (shapeTable != kODNULL))
  808.             {
  809.                 CShape* shape = shapeTable[intIndex];
  810.                 this->AddShape(shape);
  811.             }
  812.         }
  813.             
  814.     CATCH_ALL
  815.         validLink = kODFalse;
  816.     ENDTRY
  817.     
  818.     return validLink;
  819. }
  820.  
  821.  
  822. //---------------------------------------------------------------------------------------
  823. //    CPublishLink::ShowLinkInfoDialog
  824. //
  825. //    Description:    Post the Link Source Info dialog and handle the results.
  826. //---------------------------------------------------------------------------------------
  827.  
  828. void CPublishLink::ShowLinkInfoDialog(Environment* ev)
  829. {
  830.     
  831.     ODLinkInfoResult infoResult;
  832.     ODLinkSource *linkSource = this->GetODLinkSource();
  833.     
  834.     // Get a facet to pass to ShowLinkSourceInfo
  835.     TempODFrameFacetIterator facets(ev,fDrawEditor->GetFirstSourceFrame(ev));
  836.  
  837.     if ( linkSource->ShowLinkSourceInfo(ev, 
  838.                                     facets.Current(),
  839.                                     this->GetUpdateID(),
  840.                                     !fDrawEditor->IsReadOnly(),
  841.                                     &infoResult) )
  842.     {
  843.         switch (infoResult.action) 
  844.         {
  845.             case kODLinkInfoBreakLink:
  846.                 CBreakLinkSourceCommand* command = new CBreakLinkSourceCommand(fDrawEditor, this);
  847.                 fDrawEditor->ExecuteCommand(ev, command);
  848.                 break;
  849.             case kODLinkInfoUpdateNow:
  850.                 
  851.                 // a manual update is always with a new update id. kODTrue = force an update.
  852.                 this->ContentUpdated(ev, fDrawEditor->GetSession(ev)->UniqueUpdateID(ev), kODTrue);
  853.                 break;
  854.                 
  855.             case kODLinkInfoOk:
  856.                 if (infoResult.autoUpdate != linkSource->IsAutoUpdate(ev))
  857.                 {
  858.                     linkSource->SetAutoUpdate(ev, infoResult.autoUpdate);
  859.  
  860.                     if (infoResult.autoUpdate && (this->GetUpdateID() != linkSource->GetUpdateID(ev)))
  861.                         this->ContentUpdated(ev, this->GetUpdateID());
  862.  
  863.                 }
  864.                 break;
  865.             default:
  866.                 break;
  867.         }
  868.     }
  869. }
  870.  
  871. //---------------------------------------------------------------------------------------
  872. //    CPublishLink::RevealLink
  873. //
  874. //    Description:    Select the link's content. Assumes that the Document has already been
  875. //  brought to the front, and the part activated.
  876. //---------------------------------------------------------------------------------------
  877.  
  878. void CPublishLink::RevealLink(Environment* ev)
  879. {
  880.     // until we have a special way of revealing a link just select it.
  881.     
  882.     fSelection->CloseSelection(ev);
  883.     
  884.     COrdListIterator iter(fShapeList);
  885.     for (CShape* shape = (CShape*)iter.First(); iter.IsNotComplete(); shape = (CShape*)iter.Next())
  886.     {
  887.         fSelection->AddToSelection(ev, shape, kODTrue);
  888.     }
  889. }
  890.  
  891. //=============================================================================
  892. //    class CSubscribeLink
  893. //=============================================================================
  894.  
  895. //-----------------------------------------------------------------------------
  896. //    CSubscribeLink::CSubscribeLink
  897. //
  898. //    Description:  This constructor is used when creating the object due to 
  899. //  a paste as result indicating that a link is to be created.
  900. //-----------------------------------------------------------------------------
  901.  
  902. CSubscribeLink::CSubscribeLink(ODLink* odLink, CSelection* selection,
  903.                         ODLinkInfo& linkInfo, ODPasteAsResult& paResult, ODBoolean defaultIsMerge)
  904. {
  905.     fODLink = odLink;  // It was acquired by the caller
  906.     fODID = kODNULL;  // used when internalizing a link from storage
  907.     
  908.     fDrawEditor = selection->GetDrawEditor();
  909.     
  910.     // Copy link info
  911.     fLinkInfo = linkInfo;
  912.     fPasteAsResult = paResult;
  913.     fDefaultIsMerge = defaultIsMerge;
  914.     
  915.     fPublishLinks = new COrderedList;
  916.     
  917.     fSelection = selection;
  918.     fSelectedCount = 0;
  919.     fRegistered = kODFalse;
  920.     fWasRemoved = kODFalse;
  921.     fRemovedShapes = kODFalse;
  922.     
  923.     fShapeList = new COrderedList;
  924.     
  925.     fSubscribeContent = new CSubscribeContent(fDrawEditor, fShapeList, this);
  926.     
  927.     fCommand = kODNULL;
  928.     
  929.     fOriginPoint.x = 50;  // Default position for first update.
  930.     fOriginPoint.y = 50;
  931. }
  932.  
  933. //-----------------------------------------------------------------------------
  934. //    CSubscribeLink::CSubscribeLink
  935. //
  936. //     Description:    This constructor is called when creating a link object while 
  937. //     internalizing.Additional values are initialized in the InternalizeLink method
  938. //-----------------------------------------------------------------------------
  939.  
  940. CSubscribeLink::CSubscribeLink(CSelection* selection)
  941. {    
  942.     // Theoretically, the constructor could do the internalization to ensure
  943.     // complete initialization, and allow failures to throw back to the caller (CDrawContent::InitializeSubLinks)
  944.     // to catch.  Currently, InternalizeLink is called immediately after this constructor, and catches failures
  945.     // itself, returning kODFalse for a failure.
  946.     
  947.     fODLink = kODNULL;  
  948.     fODID = kODNULL;    // used when internalizing a link from storage
  949.     
  950.     fDrawEditor = selection->GetDrawEditor();
  951.         
  952.     fPublishLinks = new COrderedList;
  953.     
  954.     fSelection = selection;
  955.     fSelectedCount = 0;
  956.     fRegistered = kODFalse;
  957.     fWasRemoved = kODFalse;
  958.     fRemovedShapes = kODFalse;
  959.     
  960.     fShapeList = new COrderedList;
  961.     
  962.     fSubscribeContent = new CSubscribeContent(fDrawEditor, fShapeList, this);
  963.     
  964.     fCommand = kODNULL;
  965. }
  966.  
  967.  
  968. //-----------------------------------------------------------------------------
  969. //    CSubscribeLink::~CSubscribeLink
  970. //-----------------------------------------------------------------------------
  971.  
  972. CSubscribeLink::~CSubscribeLink()
  973. {
  974.     ODSafeReleaseObject(fODLink);
  975.         
  976.     delete fPublishLinks;
  977.     delete fSubscribeContent;
  978.     delete fShapeList;
  979.     
  980.     delete fLinkInfo.kind;
  981. }
  982.  
  983. //-----------------------------------------------------------------------------
  984. //    CSubscribeLink::Subscribe
  985. //
  986. //    Description:    Set our shapes subscriber to this, adjust the counts so
  987. //    that this link will be selected and unselected when it should be. Add to part
  988. //    content model.
  989. //-----------------------------------------------------------------------------
  990.  
  991. void    CSubscribeLink::Subscribe(Environment* ev)
  992. {
  993.     // This does nothing when a link is created from PasteAs, as the list starts out empty
  994.     // When the link itself is internalized due to paste or drop, this is where its shapes 
  995.     // get wired up to it.
  996.         
  997.     COrdListIterator shapeIter(fShapeList);
  998.     for (CShape* shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
  999.     {
  1000.         shape->Subscribe(ev, this);
  1001.         if (shape->IsSelected())
  1002.             ++fSelectedCount;
  1003.     }
  1004.     
  1005.     if (fSelectedCount != 0)
  1006.     {
  1007.         fSelection->IncrementPartialSubscribeCount(1);
  1008.         if (fSelectedCount == fShapeList->Count())
  1009.             fSelection->AddSubscribeLink(this);
  1010.     
  1011.     }
  1012.     
  1013.     this->AddToPart(ev);
  1014.  
  1015. }
  1016.  
  1017.  
  1018. //-----------------------------------------------------------------------------
  1019. //    CSubscribeLink::PostCloneInternalizeLink
  1020. //
  1021. //    Description:    Complete the internalization process after cloning is done
  1022. //-----------------------------------------------------------------------------
  1023.  
  1024. ODBoolean CSubscribeLink::PostCloneInternalizeLink(Environment* ev,  ODDraft* toDraft, CShape* shape)
  1025. {
  1026.     ODBoolean result = kODTrue;
  1027.             
  1028.     // for the case of a single embedded part, a shape object was not created until
  1029.     // after cloning was done, so we had to defer attatching it to any links.
  1030.     
  1031.     if (shape)
  1032.     {
  1033.         this->AddShape(shape);
  1034.     }
  1035.             
  1036.  
  1037.     if (fODLink == kODNULL)
  1038.     {            
  1039.         result = toDraft->IsValidID(ev, fODID);
  1040.         
  1041.         if (result)
  1042.             fODLink = toDraft->AcquireLink(ev, fODID, kODNULL);
  1043.     }
  1044.     
  1045.     
  1046.     if (result)
  1047.     {
  1048.         // We don't call Subscribe here because wan't to defer calling AddToPart, which is called from there.
  1049.         
  1050.         // The problem is that for an automatic link, that can precipitate a synchronous call 
  1051.         // to LinkUpdated, when the part is registered. That currently blows away the current 
  1052.         // selection. If 'this' is the content of the selection that leaves things in kind of a
  1053.         // mess.  Instead, the caller has to copy fSubscribeLinks (CPasteCommand and CDropCommand
  1054.         // will anyway, for undo reasons), and then iterate the copied list to add the links to
  1055.         // the part after internalization is all done.
  1056.         
  1057.         // The case where this could happen is if a destination was copied, the source then modified
  1058.         // the destination then pasted.  This would cause the pasted new destiantion to update immeditately
  1059.     
  1060.         // However, we do have to 'subscribe' all our internalized shapes so that any publishers that enclose
  1061.         // this link will behave correctly  with respect to those shapes and this subscribe link.
  1062.         
  1063.         COrdListIterator shapeIter(fShapeList);
  1064.         for (CShape* shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
  1065.         {
  1066.             shape->Subscribe(ev, this);
  1067.             
  1068.             // When the shapes were added, they were not yet part of the selection, even if it was
  1069.             // the Selection content that was internalizing. If the shapes were added to the selection
  1070.             // then it was before they pointed to this subscribe link.  The link itself is already in
  1071.             // the appropriate content list, so we just need to update fSelectedCount
  1072.             
  1073.             if (shape->IsSelected())
  1074.                 ++fSelectedCount;
  1075.         }
  1076.     }
  1077.  
  1078.     return result;
  1079.     
  1080. }
  1081.  
  1082. //-----------------------------------------------------------------------------
  1083. //    CSubscribeLink::Unsubscribe
  1084. //
  1085. //    Description:    Remove from part, adjust selection, clear refernces in 
  1086. //  contained shapes.  Inverse operation of Subscribe.
  1087. //-----------------------------------------------------------------------------
  1088.  
  1089. void  CSubscribeLink::Unsubscribe(Environment* ev)
  1090. {
  1091.     CShape* shape;
  1092.  
  1093.     // before we mess anything up, we need to see if this link is part of 
  1094.     // a clipboard promise.  This would be true iff all our content is
  1095.     // in a clipboard promise.  
  1096.     ODBoolean promised = kODTrue;
  1097.     
  1098.     COrdListIterator ite(fShapeList);
  1099.     for (shape = (CShape*)ite.First(); ite.IsNotComplete(); shape = (CShape*)ite.Next())
  1100.     {
  1101.         if (!shape->IsPromisedToClipboard())
  1102.         {
  1103.             promised = kODFalse;
  1104.             break;
  1105.         }
  1106.     }
  1107.     
  1108.     if (promised)
  1109.         ::ResolveClipboardPromises(ev, fDrawEditor->GetSession(ev));
  1110.  
  1111.     this->RemoveFromPart(ev, kODFalse); // Remove this from the part, but don't remove any shapes!
  1112.  
  1113.     if (fSelectedCount == fShapeList->Count())
  1114.     {
  1115.         fSelection->RemoveSubscribeLink(this);
  1116.     }
  1117.     
  1118.     if (fSelectedCount != 0)
  1119.     {
  1120.         fSelection->IncrementPartialSubscribeCount(-1);
  1121.         fSelectedCount = 0;
  1122.     }
  1123.     
  1124.     COrdListIterator shapeIter(fShapeList);
  1125.     for (shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
  1126.     {
  1127.         shape->Unsubscribe(ev);
  1128.     }
  1129.     
  1130.     
  1131. }
  1132.  
  1133. //-----------------------------------------------------------------------------
  1134. //    CSubscribeLink::Publish
  1135. //
  1136. //     Description:    This is called for each contained destination link by a publisher
  1137. //     when it is 'published'. 
  1138. //-----------------------------------------------------------------------------
  1139.  
  1140. void CSubscribeLink::Publish(Environment* ev, CPublishLink* publishLink)
  1141. {
  1142.     
  1143.     fPublishLinks->AddLast(publishLink);
  1144.     
  1145.     
  1146.     COrdListIterator shapeIter(fShapeList);
  1147.     for (CShape* shape = (CShape*)shapeIter.First(); shapeIter.IsNotComplete(); shape = (CShape*)shapeIter.Next())
  1148.     {
  1149.         // Don't call AddShape(ev,shape), because it calls shape->Publish. A subscribed shape need only 
  1150.         // point to its subsribe link and an embedded frame  already has status kODInLinkDestination, which
  1151.         // takes precedence over kODInLinkSource.
  1152.         
  1153.         // This just adds the shape to the publisher's shape list. When a source link is first published
  1154.         // it has a list consisting of only it's non-subscribed shapes and a list of subscribers, then it 
  1155.         // get's the rest of the shapes by Publishing it's subscribers.
  1156.         
  1157.         publishLink->AddShape(shape);
  1158.         
  1159.     }
  1160.     
  1161. }
  1162.  
  1163. //-----------------------------------------------------------------------------
  1164. //    CSubscribeLink::Unpublish
  1165. //
  1166. //    Description:    Remove the indicated CPublishLink from our list of publishers
  1167. //-----------------------------------------------------------------------------
  1168.  
  1169. void  CSubscribeLink::Unpublish(Environment* ev, CPublishLink* publishLink)
  1170. {
  1171.     fPublishLinks->Remove(publishLink);
  1172.     
  1173.     // no need to do anything with our shapes, they're still subscribed, and are not 
  1174.     // directly affected by the change in status.
  1175. }
  1176.  
  1177.  
  1178. //-----------------------------------------------------------------------------
  1179. //    CSubscribeLink::AddToPart
  1180. //
  1181. //    Description:  Add this link to the part's content model.  If this removed
  1182. //     shapes from the content model when RemoveFromPart was called, then add them
  1183. //    back as well.  Adjust part's registration for update notification.
  1184. //-----------------------------------------------------------------------------
  1185.  
  1186. void CSubscribeLink::AddToPart(Environment *ev)
  1187. {
  1188.     fDrawEditor->AddSubscribeLink(this);
  1189.     
  1190.     if (fRemovedShapes)
  1191.     {
  1192.         // Add my shapes to the part
  1193.         COrdListIterator iter(fShapeList);
  1194.         for (CShape* shape = (CShape*)iter.First();
  1195.                 iter.IsNotComplete(); 
  1196.                 shape = (CShape*)iter.Next())
  1197.         {
  1198.             fDrawEditor->AddShape(ev, shape);
  1199.         }
  1200.         
  1201.         fRemovedShapes = kODFalse;
  1202.     }
  1203.     
  1204.     fWasRemoved = kODFalse;
  1205.     this->Register(ev);
  1206.     
  1207. }
  1208.  
  1209. //-----------------------------------------------------------------------------
  1210. //    CSubscribeLink::RemoveFromPart
  1211. //
  1212. //    Description:    Remove this from the part's content model, if indicated
  1213. //    remove contained shapes from the part as well.  Adjust part's registration
  1214. //     for update notification.
  1215. //-----------------------------------------------------------------------------
  1216.  
  1217. void CSubscribeLink::RemoveFromPart(Environment* ev, ODBoolean doRemoveShapes)
  1218. {
  1219.     fDrawEditor->RemoveSubscribeLink(this);
  1220.     
  1221.     fWasRemoved = kODTrue;
  1222.  
  1223.     // Remove my shapes from the part: When undoing a paste, or redoing a cut or clear, 
  1224.     // It's possible that the shapes that were in the link originally were replaced by
  1225.     // link updates.  So the responsiblility for removing its shapes is delegated to the
  1226.     // link itself.
  1227.     
  1228.     if (doRemoveShapes)
  1229.     {
  1230.         fRemovedShapes = kODTrue;
  1231.         
  1232.         COrdListIterator iter(fShapeList);
  1233.         for (CShape* shape = (CShape*)iter.First();
  1234.                 iter.IsNotComplete(); 
  1235.                 shape = (CShape*)iter.Next())
  1236.         {
  1237.             if (shape->IsSelected())
  1238.                 fSelection->RemoveFromSelection(ev, shape, kODFalse);
  1239.                 
  1240.             fDrawEditor->RemoveShape(ev, shape);
  1241.         }
  1242.     }
  1243.     
  1244.     this->Unregister(ev);
  1245.     
  1246. }
  1247.  
  1248. //-----------------------------------------------------------------------------
  1249. //    CSubscribeLink::Register
  1250. //
  1251. //    Description:  Make sure that the part is registered with the ODLink for 
  1252. //    automatic update notification if appropriate.
  1253. //-----------------------------------------------------------------------------
  1254.  
  1255. void CSubscribeLink::Register(Environment* ev)
  1256. {
  1257.  
  1258.     if (fRegistered) return;
  1259.     if (!fODLink) return;  // link hasn't finished being internalized yet!
  1260.     
  1261.     ODUpdateID odID = fODLink->GetUpdateID(ev);
  1262.     ODBoolean needsUpdate = (fLinkInfo.change != odID);
  1263.  
  1264.     // If it's an automatic, OR if it's never been updated, then register for an automatic update
  1265.     // The later case is for creating a cross document link.  The actual link won't be created 
  1266.     // til after the paste or drop has completed, so we have to register for an update at that time.
  1267.     // simply calling LinkUpdated (as per DR3 recipe)  now won't get us any content in that case.
  1268.     // Once the first real update has been received, LinkUpdated will 'Unregister' any non-automatic
  1269.     // links that were registered here.
  1270.     
  1271.     if (fLinkInfo.autoUpdate  || (fShapeList->Count() == 0))
  1272.     {
  1273.         //--- Register for automatic updates ---
  1274.         // First determine if another subscriber with the same ODLink as ours already registered
  1275.         
  1276.         ODBoolean alreadyRegistered = kODFalse;
  1277.         COrdListIterator iter(fDrawEditor->GetSubscribeLinks());
  1278.         for (CSubscribeLink* subscriber = (CSubscribeLink*)iter.First(); iter.IsNotComplete(); subscriber = (CSubscribeLink*)iter.Next())
  1279.         {
  1280.             if ((subscriber != this) && fODLink->IsEqualTo(ev, subscriber->GetODLink())
  1281.                 && subscriber->IsRegistered())
  1282.             {
  1283.                 alreadyRegistered = TRUE;
  1284.                 break;
  1285.             }
  1286.         }
  1287.         
  1288.         // before registering, set our flag, so the update that may come during RegisterDependent
  1289.         // will recognize this as an object requireing  an automated update.
  1290.         
  1291.         fRegistered = TRUE;
  1292.  
  1293.         if (!alreadyRegistered)
  1294.         {
  1295.             fODLink->RegisterDependent(ev, fDrawEditor->GetODPart(), fLinkInfo.change);
  1296.             // part::LinkUpdated call will be generated if necessary
  1297.             needsUpdate = kODFalse;
  1298.         }
  1299.     }
  1300.  
  1301.     // Now that even a manual link is registered for the first instance, this only happens 
  1302.     // when we're registering a link for which a previously registered subscriber existed in
  1303.     // this part.
  1304.     
  1305.     if (needsUpdate)
  1306.     {
  1307.         TRY
  1308.             this->LinkUpdated(ev, odID);
  1309.         CATCH_ALL
  1310.             // Theory is that the only error we care about is kODErrCannotEstablishLink
  1311.             // and that should only happen during ODPart::LinkUpdated, but don't propagate
  1312.             // update if LinkUpdated failed.
  1313.             
  1314.             return;
  1315.         ENDTRY
  1316.         
  1317.         fDrawEditor->ContentUpdated(ev, odID);
  1318.         fDrawEditor->SetDirty(ev);
  1319.     }
  1320. }
  1321.  
  1322.  
  1323. //-----------------------------------------------------------------------------
  1324. //    CSubscribeLink::Unregister
  1325. //
  1326. //    Description:    Unregister the part from the ODLink if appropriate.
  1327. //-----------------------------------------------------------------------------
  1328.  
  1329. void CSubscribeLink::Unregister(Environment* ev)
  1330. {
  1331.     if (!fRegistered) return;
  1332.  
  1333.     if (fLinkInfo.autoUpdate  || (fShapeList->Count() == 0))
  1334.     {
  1335.         //--- Unregister for automatic updates ---
  1336.         // First determine if another subscriber with the same ODLink as ours is still registered
  1337.         
  1338.         ODBoolean lastOne = kODTrue;
  1339.         
  1340.         COrdListIterator iter(fDrawEditor->GetSubscribeLinks());
  1341.         for (CSubscribeLink* subscriber = (CSubscribeLink*)iter.First(); iter.IsNotComplete(); subscriber = (CSubscribeLink*)iter.Next())
  1342.         {
  1343.             if ((subscriber != this) && fODLink->IsEqualTo(ev, subscriber->GetODLink())
  1344.                 && subscriber->IsRegistered())
  1345.             {
  1346.                 lastOne = kODFalse;
  1347.                 break;
  1348.             }
  1349.         }
  1350.  
  1351.         if (lastOne)    // this is the only registered link
  1352.         {
  1353.             fODLink->UnregisterDependent(ev, fDrawEditor->GetODPart());
  1354.         }
  1355.     }
  1356.  
  1357.     fRegistered = kODFalse;
  1358. }
  1359.  
  1360.  
  1361. //-----------------------------------------------------------------------------
  1362. //    CSubscribeLink::LinkUpdated
  1363. //
  1364. //    Description:  Handle the notification that updated content is available or 
  1365. //    respond to a user's request to update a manual link.
  1366. //-----------------------------------------------------------------------------
  1367.  
  1368. void CSubscribeLink::LinkUpdated(Environment* ev, ODUpdateID id)
  1369. {
  1370.  
  1371.     ODLinkKey key;
  1372.     ODLink *link = this->GetODLink();
  1373.             
  1374.     if (link->Lock(ev, 0, &key))
  1375.     {
  1376.  
  1377.         ODStorageUnit*    su = kODNULL;
  1378.         ODVolatile(su);
  1379.             
  1380.         TRY
  1381.  
  1382.             su = link->GetContentStorageUnit(ev, key);
  1383.             
  1384.         CATCH(kODErrCannotEstablishLink)
  1385.             link->Unlock(ev, key);
  1386.             
  1387.             if (fCommand)
  1388.             {
  1389.                 fCommand->AbortLink(ev);
  1390.                 fCommand = kODNULL;
  1391.             }
  1392.             
  1393.             RERAISE;
  1394.         CATCH_ALL
  1395.             link->Unlock(ev, key);
  1396.             RERAISE;   // Allow callers to prevent propagating ContentUpdated to frame if we failed.
  1397.         ENDTRY
  1398.         
  1399.             // Deal with the asychronous creation of x document link sources.  The above call fails
  1400.             // On the first (synchronous) update with an x doc link.  The rest of the code won't execute until the
  1401.             // source link has actually been created and sent real data.
  1402.             
  1403.             // All links were initially registered even if manual until the first update is received.
  1404.             // correct the inconsistancy if it exists.
  1405.             if(!fLinkInfo.autoUpdate && fRegistered)
  1406.                 this->Unregister(ev);
  1407.                     
  1408.             // For a copy/paste-as created link, we've waited for the first update to create a kODEndAction
  1409.             if (fCommand)
  1410.             {
  1411.                 fCommand->CompleteLink(ev);
  1412.                 fCommand = kODNULL;
  1413.             }
  1414.             
  1415.             // We're going to use the selection because it knows how to move stuff and we want to be able 
  1416.             // to move the new content to where the old content was
  1417.             
  1418.             // First take a snapshot of the selection so we can restore it after we're done
  1419.             
  1420.             COrderedList tempShapeList;
  1421.             COrdListIterator iter(fSelection->GetShapeList());
  1422.             for (CShape* shape = (CShape*)iter.First();
  1423.                 iter.IsNotComplete(); 
  1424.                 shape = (CShape*)iter.Next())
  1425.             {
  1426.                 // Don't list any of this link's shapes, cuz they're about to get blown away
  1427.                 if (shape->GetSubscribeLink() != this)
  1428.                     tempShapeList.AddLast(shape);
  1429.             }
  1430.  
  1431.             // Need to know whether the new shapes should remain selected when the update is done.
  1432.             ODBoolean thisLinkWasSelected = fSelectedCount == fShapeList->Count();
  1433.             
  1434.             // Now close the selection
  1435.             fSelection->CloseSelection(ev);
  1436.             
  1437.             ODPoint newPosition(50, 50);  // default location for first update. Same as for paste.
  1438.             ODBoolean first = kODTrue;
  1439.             
  1440.             // Out with the Old
  1441.             
  1442.             while (fShapeList->Count() != 0)
  1443.             {
  1444.                 CShape *shape = (CShape*)fShapeList->RemoveFirst();
  1445.                 
  1446.                 ODRect shapeRect;
  1447.                 shape->GetBoundingBox(&shapeRect);
  1448.                 
  1449.                 if (first || shapeRect.left < fOriginPoint.x)
  1450.                     fOriginPoint.x = shapeRect.left;
  1451.                 if (first || shapeRect.top < fOriginPoint.y)
  1452.                     fOriginPoint.y = shapeRect.top;
  1453.                     
  1454.                 first = kODFalse;
  1455.                 
  1456.                 // Not necessary since we are closing the selection first, but if we change
  1457.                 // and do this without closing the selection then we need to do this.
  1458.                 if (shape->IsSelected())
  1459.                     fSelection->RemoveFromSelection(ev, shape, kODFalse);
  1460.                 
  1461.                 fDrawEditor->RemoveShape(ev, shape);
  1462.                 
  1463.                 shape->SetInLimbo(ev, kODTrue);
  1464.                 shape->Removed(ev, kODTrue);
  1465.                 
  1466.                 // Resolve any promises for shapes that are about to be blown away. 
  1467.                 // Note that this will only happen once, as the rest of the shapes 
  1468.                 // will no longer be promised after the first time.
  1469.                 if (shape->IsPromisedToClipboard())
  1470.                 {
  1471.                     ::ResolveClipboardPromises(ev, fDrawEditor->GetSession(ev));
  1472.                 }
  1473.                 
  1474.                 delete shape;
  1475.             }
  1476.             
  1477.             // In with the new
  1478.             
  1479.             ODFrame* frame = kODNULL;
  1480.             ODVolatile(frame);
  1481.             
  1482.             TRY
  1483.                 frame = fDrawEditor->GetFirstSourceFrame(ev);
  1484.                 CCloneInfo cloneInfo(0, su->GetDraft(ev), frame, kODCloneFromLink);
  1485.                 
  1486.             // If the user's choice in PasteAs was different from the default for the original link content
  1487.             // then force the updated content to be internalized in the chosen way
  1488.             
  1489.             // User chose to embed intrinsic content in a frame.
  1490.             if (!fPasteAsResult.mergeSetting && fDefaultIsMerge)
  1491.                 fSubscribeContent->HandleTranslateContent(ev, su, &cloneInfo, kODTrue);
  1492.                 
  1493.             // User chose to merge a single embedded DrawEditor frame. 
  1494.             else if (fPasteAsResult.mergeSetting && !fDefaultIsMerge)
  1495.                 fSubscribeContent->HandleTranslateContent(ev, su, &cloneInfo, kODFalse);
  1496.             
  1497.             // Otherwise, the user's choice in PasteAs was the same as the default for the original content,
  1498.             // so internalize the current content in the default way.
  1499.             
  1500.             else
  1501.                 fSubscribeContent->HandleInternalizeContent(ev, su, &cloneInfo);
  1502.                             
  1503.                 link->Unlock(ev, key);
  1504.                 
  1505.             CATCH_ALL
  1506.                 link->Unlock(ev, key);
  1507.                 
  1508.                 // A cool thing to do:  Cache the old shapes before attempting to internalize.
  1509.                 // restore them to the link and the part here, or delete them below if internalization
  1510.                 // succeeds.
  1511.                 
  1512.                 RERAISE;  // Allow callers to prevent propagating ContentUpdated to frame if we failed.
  1513.             ENDTRY
  1514.                 
  1515.             // Adjust positioning of new content
  1516.             
  1517.             // First select our new content
  1518.             this->AddToSelection(ev, kODFalse);
  1519.             
  1520.             
  1521.             ODRect box;
  1522.             fSelection->GetSelectionRectangle(&box);
  1523.         
  1524.             fSelection->OffsetSelection(ev, 
  1525.                                         frame, 
  1526.                                         fOriginPoint.x - box.left, 
  1527.                                         fOriginPoint.y - box.top);
  1528.                                         
  1529.             fLinkInfo.change = id;
  1530.             fLinkInfo.changeTime = this->GetODLink()->GetChangeTime(ev);
  1531.  
  1532.             // Restore the selection to it's original content
  1533.             
  1534.             // if this link was only partially selected, we don't know which of our shapes to leave selected
  1535.             // because there's no 1-1 correspondence between the old shapes and the replacement shapes, so
  1536.             // just close the selection.
  1537.             
  1538.             if (!thisLinkWasSelected)
  1539.                 fSelection->CloseSelection(ev);
  1540.             
  1541.             // Add the selected shapes that were not affected by this update back into the selection.
  1542.             while (tempShapeList.Count() != 0)
  1543.             {
  1544.                 CShape* shape = (CShape*)tempShapeList.RemoveFirst();
  1545.                 fSelection->AddToSelection(ev, shape, kODFalse);
  1546.             }
  1547.             
  1548.             
  1549.             // Here's where we propagate changes to any sources which contain this destination.
  1550.             // Since sources always contain whole destinations, every object in the destination
  1551.             // has exactly the same publishers, so we keep them here (in the subscribe link) rather than dealing with each
  1552.             // contained shape.
  1553.  
  1554.             COrdListIterator iter2(fPublishLinks);
  1555.             for (CPublishLink* link = (CPublishLink*)iter2.First(); iter2.IsNotComplete(); link = (CPublishLink*)iter2.Next())
  1556.             {
  1557.                 link->ContentUpdated(ev, id);
  1558.             }
  1559.     
  1560.             // Don't call DrawEditor::ContentUpdated here, because we could be updating multiple
  1561.             // CSubscribeLinks from the same notification with the same updateID.
  1562.             // DrawEditor::LinkUpdated does it once after the entire update is complete.
  1563.     
  1564.  
  1565.     }
  1566. }
  1567.  
  1568. //-----------------------------------------------------------------------------
  1569. //    CSubscribeLink::AddShape
  1570. //
  1571. //    Description:    Add a shape to this subscribe link and add it to any publishers
  1572. //  it is contained in.
  1573. //-----------------------------------------------------------------------------
  1574.  
  1575. void CSubscribeLink::AddShape(CShape* shape)
  1576. {
  1577.     // Shapes are normally added to a subscribe link when it or it is internalized from a storage unit
  1578.     // When shapes are removed from and added to the part, all the shapes
  1579.     // within a CSubscribeLink are added and removed together, but are left
  1580.     // in the fShapeList list.
  1581.     
  1582.     if (!fWasRemoved)
  1583.     {
  1584.         fShapeList->AddLast(shape);
  1585.         if (shape->IsSelected())
  1586.             fSelectedCount++;
  1587.     }
  1588.     
  1589.     COrdListIterator ite(fPublishLinks);
  1590.     for (CPublishLink* plink = (CPublishLink*)ite.First(); ite.IsNotComplete(); plink = (CPublishLink*)ite.Next())
  1591.         plink->AddShape(shape);
  1592.         
  1593.  
  1594. }
  1595.  
  1596. //-----------------------------------------------------------------------------
  1597. //    CSubscribeLink::AddShape
  1598. //
  1599. //     Description: This method is called when a newly internalize shape is added to a link. 
  1600. //    In this case, the shapes were added to the part, but had no subscriber pointers at 
  1601. //    the time.  Now we have make the shape a subscriber and then add it to our content.
  1602. //-----------------------------------------------------------------------------
  1603.  
  1604. void CSubscribeLink::AddShape(Environment* ev, CShape* shape)
  1605. {    
  1606.     
  1607.     // now make it a subscriber
  1608.     shape->Subscribe(ev, this);
  1609.     
  1610.     // now our ordinary AddShape method that wasn't called when the shape was added to the part
  1611.     this->AddShape(shape);
  1612.         
  1613. }
  1614.  
  1615. //-----------------------------------------------------------------------------
  1616. //    CSubscribeLink::RemoveShape
  1617. //
  1618. //    Description:    If the link was not removed from the part, then remove the
  1619. //     shape from this link and remove it from any link sources this is contained in.
  1620. //-----------------------------------------------------------------------------
  1621.  
  1622. void CSubscribeLink::RemoveShape(CShape* shape)
  1623. {
  1624.     // Shapes are normally removed from a subscribe link when it updates.
  1625.     // When shapes are removed from he part, all the shapes
  1626.     // within a CSubscribeLink are added and removed together, but are left
  1627.     // in the fShapeList list.  
  1628.     
  1629.     if (!fWasRemoved)
  1630.     {
  1631.         fShapeList->Remove(shape);
  1632.         if (shape->IsSelected())
  1633.             fSelectedCount--;
  1634.     }
  1635.     
  1636.     COrdListIterator ite(fPublishLinks);
  1637.     for (CPublishLink* plink = (CPublishLink*)ite.First(); ite.IsNotComplete(); plink = (CPublishLink*)ite.Next())
  1638.         plink->RemoveShape(shape);
  1639.         
  1640. }
  1641.  
  1642.  
  1643. //-----------------------------------------------------------------------------
  1644. //    CSubscribeLink::ShapeSelected
  1645. //
  1646. //    Description:  Keep track of how many of of our shapes have been selected
  1647. //    and inform the selection when it's count of partially selected links and/or
  1648. //    it's list of fully selected links needs to be updated.
  1649. //-----------------------------------------------------------------------------
  1650.  
  1651. void CSubscribeLink::ShapeSelected(ODBoolean selectState)
  1652. {
  1653.     short oldCount = fSelectedCount;
  1654.     
  1655.     if (selectState)
  1656.     {
  1657.         ++fSelectedCount;
  1658.         ASSERT(fSelectedCount <= fShapeList->Count(), kODErrAssertionFailed);
  1659.         
  1660.         if (oldCount == 0)
  1661.         {
  1662.             fSelection->IncrementPartialSubscribeCount(1);
  1663.         }
  1664.         
  1665.         if (fSelectedCount == fShapeList->Count())
  1666.         {
  1667.             fSelection->AddSubscribeLink(this);
  1668.         }
  1669.     }
  1670.     else
  1671.     {
  1672.         --fSelectedCount;
  1673.         ASSERT(fSelectedCount >= 0, kODErrAssertionFailed);
  1674.         
  1675.         if (oldCount == fShapeList->Count())
  1676.         {
  1677.             fSelection->RemoveSubscribeLink(this);
  1678.         }
  1679.         
  1680.         if (fSelectedCount == 0)
  1681.         {
  1682.             fSelection->IncrementPartialSubscribeCount(-1);
  1683.         }
  1684.     }
  1685.  
  1686. }
  1687.  
  1688. //-----------------------------------------------------------------------------
  1689. //    CSubscribeLink::AddToSelection
  1690. //
  1691. //    Description:  Add our shapes to the selection. Used to select subscribed
  1692. //  shapes when undoing or redoing certain commands.
  1693. //-----------------------------------------------------------------------------
  1694.  
  1695. void CSubscribeLink::AddToSelection(Environment* ev, ODBoolean drawHandles)
  1696. {
  1697.     COrdListIterator iter(fShapeList);
  1698.     for (CShape* shape = (CShape*)iter.First();
  1699.         iter.IsNotComplete(); 
  1700.         shape = (CShape*)iter.Next())
  1701.     {
  1702.         fSelection->AddToSelection(ev, shape, drawHandles);
  1703.     }
  1704.     
  1705. }
  1706.  
  1707. //-----------------------------------------------------------------------------
  1708. //    CSubscribeLink::RemoveShapes
  1709. //
  1710. //    Description:    When committing a command in a state in which the shapes are
  1711. //    removed from the content, handle the removal and deletion of contained shapes.
  1712. //-----------------------------------------------------------------------------
  1713.  
  1714. void CSubscribeLink::RemoveShapes(Environment* ev, ODBoolean commit)
  1715. {
  1716.  
  1717.     // This is only called when commiting removal of shapes and link
  1718.     ASSERT(commit == kODTrue, kODErrAssertionFailed);
  1719.     
  1720.     while (fSubscribeContent->Count() != 0)
  1721.     {
  1722.         CShape* shape = (CShape*)fShapeList->First();
  1723.     
  1724.         // We're going to blow the shape away.  Don't want dangling pointers used
  1725.         // later to fulfill a promise. In case fulfilling the promise also causes this link
  1726.         // to be externalized, then all of our shapes are promised, and ResolveClipboardPromises will happen on
  1727.         // the first shape.  However, due to that case, it must happen before we actually remove
  1728.         // any shapes from our shape list, otherwise the link won't externalize properly.
  1729.         
  1730.         if (shape->IsPromisedToClipboard())
  1731.         {
  1732.             ::ResolveClipboardPromises(ev, fDrawEditor->GetSession(ev));
  1733.         }
  1734.                 
  1735.         fShapeList->RemoveFirst();
  1736.         
  1737.         shape->SetInLimbo(ev, kODTrue);
  1738.         shape->Removed(ev, kODTrue);
  1739.         delete shape;
  1740.     }
  1741.         
  1742. }
  1743.  
  1744. //-----------------------------------------------------------------------------
  1745. //    CSubscribeLink::ExternalizeLink
  1746. //
  1747. //    Description:    Externalize the ODLink and the data defining this link.
  1748. //-----------------------------------------------------------------------------
  1749.  
  1750. void CSubscribeLink::ExternalizeLink(Environment *ev, ODStorageUnit* su, CCloneInfo* cloneInfo)
  1751. {
  1752.     ODID linkDestID = this->GetODLink()->GetID(ev);
  1753.     ODBoolean valid = kODTrue;
  1754.     
  1755.     if (cloneInfo)
  1756.     {
  1757.         linkDestID = cloneInfo->fFromDraft->Clone(ev, cloneInfo->fKey, linkDestID, kODNULLID, kODNULLID);
  1758.         valid = cloneInfo->fFromDraft->IsValidID(ev, linkDestID);
  1759.     }
  1760.         
  1761.     if (valid)
  1762.     {
  1763.     
  1764.         // store the number of shapes
  1765.         ODUShort shapeCnt = fShapeList->Count();
  1766.  
  1767.         StorageUnitSetValue(su, ev, sizeof(ODUShort), &shapeCnt);
  1768.         
  1769.         // store a reference to the link
  1770.         ODStorageUnitRef    aSURef ;
  1771.         su->GetStrongStorageUnitRef(ev, linkDestID, aSURef);
  1772.         StorageUnitSetValue(su, ev, kODStorageUnitRefSize, &aSURef);
  1773.         
  1774.         // store the link info
  1775.         StorageUnitSetValue(su, ev, sizeof(ODLinkInfo), &fLinkInfo);
  1776.         
  1777.         // link info has a string in it, we need to store that too.
  1778.         StorageUnitSetISOStrValue(    su, ev, fLinkInfo.kind);
  1779.             
  1780.         // store pasteAsResult
  1781.         StorageUnitSetValue(su, ev, sizeof(ODPasteAsResult), &fPasteAsResult);
  1782.         
  1783.         // We don't preserve the selectedKind and translateKind strings in fPaResult
  1784.         // (the selectedKind is 'given' to fLinkInfo.kind, and the translationKind 
  1785.         // was ditched after the link was initially created from pasteAs.
  1786.         
  1787.         // store the default merge setting
  1788.         StorageUnitSetValue(su, ev, sizeof(ODBoolean), &fDefaultIsMerge);
  1789.         
  1790.         
  1791.         // store the export indices for each shape in the link.
  1792.         COrdListIterator iter(fShapeList);
  1793.         for (CShape *shape = (CShape*)iter.First(); iter.IsNotComplete(); shape = (CShape*)iter.Next())
  1794.         {
  1795.             ODUShort extInd = shape->GetExternalizationIndex();
  1796.             StorageUnitSetValue(su, ev, sizeof(ODUShort), &extInd);
  1797.         }
  1798.     }
  1799.     else
  1800.     {
  1801.         ODUShort invalShapeCnt = 0;
  1802.         StorageUnitSetValue(su, ev, sizeof(ODUShort), &invalShapeCnt);
  1803.     }
  1804. }
  1805.  
  1806.  
  1807. //-----------------------------------------------------------------------------
  1808. //    CSubscribeLink::InternalizeLink
  1809. //
  1810. //    Description: Internalize an ODLink and the necessary associated data
  1811. //-----------------------------------------------------------------------------
  1812.  
  1813. ODBoolean CSubscribeLink::InternalizeLink( Environment *ev,  ODStorageUnit *su,  CCloneInfo *cloneInfo, CShape** shapeTable)
  1814. {
  1815.     ODUShort count;
  1816.     StorageUnitGetValue(su, ev, sizeof(ODUShort), &count);
  1817.     
  1818.     if (count == 0)  // link was invalid from the git go
  1819.         return kODFalse;
  1820.         
  1821.     ODBoolean validLink = kODTrue;
  1822.     ODVolatile(validLink);
  1823.     
  1824.     TRY
  1825.         
  1826.         ODStorageUnitRef    aSURef;
  1827.         StorageUnitGetValue(su, ev, kODStorageUnitRefSize, &aSURef);
  1828.         
  1829.         validLink = su->IsValidStorageUnitRef(ev, aSURef) ;
  1830.         
  1831.         StorageUnitGetValue(su, ev, sizeof(ODLinkInfo), &fLinkInfo);
  1832.         fLinkInfo.kind = StorageUnitGetISOStrValue(su, ev);
  1833.         
  1834.         StorageUnitGetValue(su, ev, sizeof(ODPasteAsResult), &fPasteAsResult);
  1835.  
  1836.         // We didn't externalize the selectedKind and translateKind strings in fPaResult
  1837.  
  1838.         StorageUnitGetValue(su, ev, sizeof(ODBoolean), &fDefaultIsMerge);
  1839.  
  1840.         if (validLink )
  1841.         {
  1842.             // we have a validated su ref for the link, so clone and get the link
  1843.             fODID = su->GetIDFromStorageUnitRef(ev, aSURef);
  1844.  
  1845.             if (cloneInfo)
  1846.                 fODID = cloneInfo->fFromDraft->Clone(ev, cloneInfo->fKey, fODID, kODNULLID, kODNULLID);
  1847.         }
  1848.         
  1849.         for (ODUShort k = 0; k < count; k++)
  1850.         {
  1851.             ODUShort intIndex;
  1852.             StorageUnitGetValue(su, ev, sizeof(short), &intIndex);
  1853.             
  1854.             if(validLink && (shapeTable != kODNULL))
  1855.             {
  1856.                 CShape *shape = shapeTable[intIndex];
  1857.                 this->AddShape(shape);
  1858.             }
  1859.         }
  1860.             
  1861.     CATCH_ALL
  1862.         validLink = kODFalse;
  1863.     ENDTRY
  1864.     
  1865.     return validLink;
  1866. }
  1867.  
  1868.  
  1869. //-----------------------------------------------------------------------------
  1870. //    CSubscribeLink::ShowCantEditDialog
  1871. //
  1872. //    Description:    Show the appropriate 'Can't Edit' dialog for a single  
  1873. //    link which prevents a content modification.
  1874. //-----------------------------------------------------------------------------
  1875.  
  1876. void CSubscribeLink::ShowCantEditDialog(Environment* ev)
  1877. {
  1878.     // Temporary until the HI specified dialog is implemented:
  1879.     // The LinkInfo dialog does all the required things, just doesn't show the 'Can't Edit' text.
  1880.     
  1881.     this->ShowLinkInfoDialog(ev);
  1882. }
  1883.  
  1884.  
  1885. //-----------------------------------------------------------------------------
  1886. //    CSubscribeLink::ShowLinkInfoDialog
  1887. //
  1888. //    Description:  Show the Link Destination Info dialog for this link,and respond
  1889. //    to the user's choices.
  1890. //-----------------------------------------------------------------------------
  1891.  
  1892. void CSubscribeLink::ShowLinkInfoDialog(Environment* ev)
  1893. {
  1894.  
  1895.     ODLinkInfoResult infoResult;
  1896.     
  1897.     // Get a facet to pass to ShowLinkDestinationInfo
  1898.     TempODFrameFacetIterator facets(ev,fDrawEditor->GetFirstSourceFrame(ev));
  1899.  
  1900.     if ( this->GetODLink()->ShowLinkDestinationInfo(ev, 
  1901.                                     facets.Current(),
  1902.                                     &fLinkInfo,
  1903.                                     !fDrawEditor->IsReadOnly(),
  1904.                                     &infoResult) )
  1905.     {
  1906.         switch (infoResult.action) 
  1907.         {
  1908.             case kODLinkInfoFindSource:
  1909.                 this->GetODLink()->ShowSourceContent(ev);
  1910.                 break;
  1911.             case kODLinkInfoBreakLink:
  1912.                 CBreakLinkCommand* command = new CBreakLinkCommand(fDrawEditor, this);
  1913.                 fDrawEditor->ExecuteCommand(ev, command);
  1914.                 break;
  1915.             case kODLinkInfoUpdateNow:
  1916.             
  1917.                 // Update now button should have been disabled if our info indicated that we're already up to
  1918.                 // up to date.  
  1919.                 
  1920.                 // For a manual update, we don't re-use the existing updateID, but generate a new one.
  1921.                 // The reason for propagating the same ID for automatic updates is to prevent runaway
  1922.                 // recursion. For a manual update, using the same ID as our last update could preciptate
  1923.                 // link cycle dialog when the id is passed to any local or containing publishers. The user
  1924.                 // in choosing to update manually, does not need to be further queried.
  1925.                 
  1926.                 ODUpdateID updateID = fDrawEditor->GetSession(ev)->UniqueUpdateID(ev);
  1927.                 
  1928.                 TRY
  1929.                     this->LinkUpdated(ev, updateID);
  1930.                     
  1931.                 CATCH_ALL
  1932.                     // Theory is that the only error we care about is kODErrCannotEstablishLink
  1933.                     // and that should only happen during ODPart::LinkUpdated, but skip propagating
  1934.                     // changes if update failed.
  1935.                     
  1936.                     break;
  1937.                 ENDTRY
  1938.                 
  1939.  
  1940.                 // store the actual update id from the link so the 'Update Now' button won't be
  1941.                 // enabled the next time unless the link actually changed.
  1942.                 
  1943.                 fLinkInfo.change = this->GetODLink()->GetUpdateID(ev);
  1944.                 
  1945.                 fDrawEditor->ContentUpdated(ev,updateID);
  1946.                 fDrawEditor->SetDirty(ev);
  1947.                 break;
  1948.                 
  1949.             case kODLinkInfoOk:
  1950.                 if (infoResult.autoUpdate != fLinkInfo.autoUpdate)
  1951.                 {
  1952.                     fLinkInfo.autoUpdate = infoResult.autoUpdate;
  1953.                     if (infoResult.autoUpdate)
  1954.                         this->Register(ev);  // Will precipitate the necessary update
  1955.                     else
  1956.                         this->Unregister(ev);
  1957.                 }
  1958.                 break;
  1959.                 
  1960.             default:
  1961.                 break;
  1962.         }
  1963.     }
  1964.     
  1965.     
  1966. }
  1967.  
  1968. //-----------------------------------------------------------------------------
  1969. //    CSubscribeLink::Count
  1970. //
  1971. //    Description: How many shapes?
  1972. //-----------------------------------------------------------------------------
  1973. ODULong CSubscribeLink::Count()
  1974. {
  1975.     return fShapeList->Count();
  1976. }
  1977.  
  1978.